FastAPIã§ã®éåæããŒã¿ããŒã¹çµ±åããã¹ã¿ãŒãã髿§èœãªãŠã§ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ãSQLAlchemyãšDatabasesã©ã€ãã©ãªã®äŸãçšããå æ¬çãªã¬ã€ãã§ãã
FastAPIããŒã¿ããŒã¹çµ±åïŒéåæããŒã¿ããŒã¹æäœã®æ·±æã
çŸä»£ã®ãŠã§ãéçºã®äžçã«ãããŠãããã©ãŒãã³ã¹ã¯åãªãæ©èœã§ã¯ãªããåºæ¬çãªèŠä»¶ã§ãããŠãŒã¶ãŒã¯é«éã§å¿çæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãæåŸ ããŠãããéçºè ã¯åžžã«ãã®æåŸ ã«å¿ããããã®ããŒã«ãæè¡ã暡玢ããŠããŸããFastAPIã¯Pythonãšã³ã·ã¹ãã ã®äžã§åŒ·åãªãã¬ãŒã ã¯ãŒã¯ãšããŠç»å Žãããã®é©ç°çãªé床ã§ç§°è³ãããŠããŸãããããã¯äž»ã«ãã®éåæçãªæ§è³ªã«ãããã®ã§ããããããé«éãªãã¬ãŒã ã¯ãŒã¯ã¯æ¹çšåŒã®äžéšã«éããŸãããã¢ããªã±ãŒã·ã§ã³ãé ãããŒã¿ããŒã¹ãåŸ ã€ã®ã«ã»ãšãã©ã®æéãè²»ãããŠãããªããããã¯é«æ§èœãšã³ãžã³ãäº€éæžæ»ã«ã¯ãŸã£ãŠãããããªãã®ã§ãã
ããã§éèŠã«ãªãã®ããéåæããŒã¿ããŒã¹æäœã§ããFastAPIã¢ããªã±ãŒã·ã§ã³ãããã»ã¹å šäœããããã¯ããããšãªãããŒã¿ããŒã¹ã¯ãšãªãåŠçã§ããããã«ããããšã§ãçã®äžŠè¡æ§ãå®çŸããé«éã§ããã ãã§ãªãæ¡åŒµæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãããã®å æ¬çãªã¬ã€ãã§ã¯ãFastAPIãšéåæããŒã¿ããŒã¹ãçµ±åããçç±ãå å®¹ãæ¹æ³ã解説ããäžçäžã®ãŠãŒã¶ãŒã«åããçã«é«æ§èœãªãµãŒãã¹ãæ§ç¯ããåãæäŸããŸãã
äžå¿æŠå¿µïŒãªãéåæI/OãéèŠãªã®ã
ã³ãŒãã«é£ã³èŸŒãåã«ãéåææäœã解決ããæ ¹æ¬çãªåé¡ãã€ãŸãI/OããŠã³ããªåŸ æ©ãçè§£ããããšãäžå¯æ¬ ã§ãã
ãããã³ã«ããçç·Žã®ã·ã§ããæ³åããŠã¿ãŠãã ãããåæçïŒããããã³ã°ïŒã¢ãã«ã§ã¯ããã®ã·ã§ãã¯äžåºŠã«äžã€ã®ã¿ã¹ã¯ãããªããŸããéã«æ°Žãå ¥ããŠç«ã«ãããæ²žéš°ãããŸã§ãã£ãšèŠå®ããŸããæ°Žã沞隰ããŠåããŠãéèãåãå§ããŸããããã¯éåžžã«éå¹ççã§ããã·ã§ãã®æéïŒCPUïŒãåŸ æ©æéïŒI/OæäœïŒã«æµªè²»ãããŠããŸãã
次ã«ãéåæçïŒãã³ããããã³ã°ïŒã¢ãã«ãèããŠã¿ãŸããããã·ã§ãã¯æ°Žãç«ã«ãããåŸ ã€ä»£ããã«ããã«éèãåãå§ããŸãããªãŒãã³ã«ãã¬ã€ãå ¥ãããããããŸããã圌ãã¯ã¿ã¹ã¯ãåãæ¿ããªãããããæéã®ãããæäœïŒãæ¹¯ãæ²žãããçŒããªã©ïŒãå®äºããã®ãåŸ ã€éã«ãè€æ°ã®äœæ¥ãé²ããããšãã§ããŸããã¿ã¹ã¯ãå®äºãããšãïŒãæ¹¯ãæ²žãããšãïŒãã·ã§ãã«éç¥ããããã®æçã®æ¬¡ã®ã¹ãããã«é²ãããšãã§ããŸãã
ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã«ãããŠãããŒã¿ããŒã¹ã¯ãšãªãAPIåŒã³åºãããã¡ã€ã«ã®èªã¿èŸŒã¿ã¯ããæ¹¯ã沞ãã®ãåŸ ã€ããšã«çžåœããŸããåŸæ¥ã®åæçãªã¢ããªã±ãŒã·ã§ã³ã¯ãäžã€ã®ãªã¯ãšã¹ããåŠçããããŒã¿ããŒã¹ã«ã¯ãšãªãéä¿¡ããããŒã¿ããŒã¹ãå¿çãããŸã§ä»ã®åä¿¡ãªã¯ãšã¹ãããããã¯ããŠã¢ã€ãã«ç¶æ ã«ãªããŸããPythonã®`asyncio`ãšFastAPIã®ãããªãã¬ãŒã ã¯ãŒã¯ã§åäœããéåæã¢ããªã±ãŒã·ã§ã³ã¯ãI/OãåŸ ã£ãŠããã¿ã¹ã¯ãå¹ççã«åãæ¿ããããšã§ãäœåãã®åææ¥ç¶ãåŠçããããšãã§ããŸãã
éåæããŒã¿ããŒã¹æäœã®äž»ãªå©ç¹ïŒ
- äžŠè¡æ§ã®åäžïŒåãããŒããŠã§ã¢ãªãœãŒã¹ã§ãã¯ããã«å€ãã®åæãŠãŒã¶ãŒãåŠçã§ããŸãã
- ã¹ã«ãŒãããã®æ¹åïŒã¢ããªã±ãŒã·ã§ã³ãããŒã¿ããŒã¹ãåŸ ã£ãŠåæ¢ããªãããã1ç§ãããã«ããå€ãã®ãªã¯ãšã¹ããåŠçã§ããŸãã
- ãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ã®åäžïŒå¿çæéãççž®ãããããšã§ããšã³ããŠãŒã¶ãŒã«ãšã£ãŠããå¿çæ§ãé«ãæºè¶³ã®ããäœéšã«ã€ãªãããŸãã
- ãªãœãŒã¹å¹çïŒCPUãšã¡ã¢ãªã®å©çšçãåäžããã€ã³ãã©ã³ã¹ãã®åæžã«ã€ãªããå¯èœæ§ããããŸãã
éåæéçºç°å¢ã®ã»ããã¢ãã
å§ããã«ã¯ãããã€ãã®äž»èŠãªã³ã³ããŒãã³ããå¿ èŠã§ããããã§ã¯ããŒã¿ããŒã¹ãšããŠPostgreSQLã䜿çšããŸããããã¯ãéåæãã©ã€ããŒã®ãµããŒããåªããŠããããã§ãããããããã®ååã¯ãéåæãã©ã€ããŒãæã€MySQLãSQLiteã®ãããªä»ã®ããŒã¿ããŒã¹ã«ãé©çšãããŸãã
1. ã³ã¢ãã¬ãŒã ã¯ãŒã¯ãšãµãŒããŒ
ãŸããFastAPIãšUvicornã®ãããªASGIãµãŒããŒãã€ã³ã¹ããŒã«ããŸãã
pip install fastapi uvicorn[standard]
2. éåæããŒã¿ããŒã¹ããŒã«ãããã®éžæ
éåæã§ããŒã¿ããŒã¹ãšéä¿¡ããããã«ã¯ãäž»ã«2ã€ã®ã³ã³ããŒãã³ããå¿ èŠã§ãïŒ
- éåæããŒã¿ããŒã¹ãã©ã€ããŒïŒããã¯ãéåæãããã³ã«ã䜿çšããŠãããã¯ãŒã¯çµç±ã§ããŒã¿ããŒã¹ãšéä¿¡ããäœã¬ãã«ã®ã©ã€ãã©ãªã§ããPostgreSQLã®å Žåã
asyncpgãããã¡ã¯ãã¹ã¿ã³ããŒãã§ããããã®é©ç°çãªããã©ãŒãã³ã¹ã§ç¥ãããŠããŸãã - éåæã¯ãšãªãã«ããŒãŸãã¯ORMïŒããã¯ãããé«ã¬ãã«ã§Pythonãããæ¹æ³ã§ã¯ãšãªãäœæããããã®ãã®ã§ããããã§ã¯2ã€ã®äººæ°ã®ãããªãã·ã§ã³ãæ¢ããŸãïŒ
databasesïŒçã®SQLå®è¡ã®ããã®ã¯ãªãŒã³ãªAPIãæäŸãããã·ã³ãã«ã§è»œéãªéåæã¯ãšãªãã«ããŒã§ããSQLAlchemy 2.0+ïŒåŒ·åã§æ©èœè±å¯ãªSQLAlchemy ORMã®ææ°ããŒãžã§ã³ã«ã¯ã`asyncio`ã®ãã€ãã£ãã§ãã¡ãŒã¹ãã¯ã©ã¹ã®ãµããŒããå«ãŸããŠããŸããããã¯ãè€éãªã¢ããªã±ãŒã·ã§ã³ã§ãã°ãã°å¥œãŸããéžæè¢ã§ãã
3. ã€ã³ã¹ããŒã«
å¿ èŠãªã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŸããããããŒã«ãããã®ãããããéžæããããäž¡æ¹ãã€ã³ã¹ããŒã«ããŠè©Šãããšãã§ããŸãã
SQLAlchemyãš`databases`ã䜿çšããPostgreSQLã®å ŽåïŒ
# Driver for PostgreSQL
pip install asyncpg
# For the SQLAlchemy 2.0+ approach
pip install sqlalchemy
# For the 'databases' library approach
pip install databases[postgresql]
ç°å¢ã®æºåãã§ããã®ã§ããããã®ããŒã«ãFastAPIã¢ããªã±ãŒã·ã§ã³ã«çµ±åããæ¹æ³ãæ¢ã£ãŠã¿ãŸãããã
æŠç¥1ïŒ`databases`ã©ã€ãã©ãªã«ããã·ã³ãã«ã
databasesã©ã€ãã©ãªã¯åªããåºçºç¹ã§ããã·ã³ãã«ã«èšèšãããŠãããåºç€ãšãªãéåæãã©ã€ããŒã®èãã©ãããŒãæäŸããå®å
šãªORMã®è€éããªãã«éåæã®çSQLã®åãäžããŠãããŸãã
ã¹ããã1ïŒããŒã¿ããŒã¹æ¥ç¶ãšã©ã€ããµã€ã¯ã«ç®¡ç
å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããªã¯ãšã¹ãããšã«ããŒã¿ããŒã¹ã«æ¥ç¶ã»åæããããããŸãããããã¯éå¹çã§ãã代ããã«ãã¢ããªã±ãŒã·ã§ã³ã®èµ·åæã«æ¥ç¶ããŒã«ã確ç«ããã·ã£ããããŠã³æã«æ£åžžã«éããŸããFastAPIã®ã€ãã³ããã³ãã©ïŒ`@app.on_event("startup")`ãš`@app.on_event("shutdown")`ïŒã¯ããã®ç®çã«æé©ã§ãã
main_databases.pyãšããååã®ãã¡ã€ã«ãäœæããŸãããïŒ
import databases
import sqlalchemy
from fastapi import FastAPI
# --- Database Configuration ---
# Replace with your actual database URL
# Format for asyncpg: "postgresql+asyncpg://user:password@host/dbname"
DATABASE_URL = "postgresql+asyncpg://user:password@localhost/testdb"
database = databases.Database(DATABASE_URL)
# SQLAlchemy model metadata (for table creation)
metadata = sqlalchemy.MetaData()
# Define a sample table
notes = sqlalchemy.Table(
"notes",
metadata,
sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column("title", sqlalchemy.String(100)),
sqlalchemy.Column("content", sqlalchemy.String(500)),
)
# Create an engine for table creation (this part is synchronous)
# The 'databases' library doesn't handle schema creation
engine = sqlalchemy.create_engine(DATABASE_URL.replace("+asyncpg", ""))
metadata.create_all(engine)
# --- FastAPI Application ---
app = FastAPI(title="FastAPI with Databases Library")
@app.on_event("startup")
async def startup():
print("Connecting to database...")
await database.connect()
print("Database connection established.")
@app.on_event("shutdown")
async def shutdown():
print("Disconnecting from database...")
await database.disconnect()
print("Database connection closed.")
# --- API Endpoints ---
@app.get("/")
def read_root():
return {"message": "Welcome to the Async Database API!"}
éèŠãªãã€ã³ãïŒ
DATABASE_URLãpostgresql+asyncpgã¹ããŒãã䜿çšããŠå®çŸ©ããŸãã- ã°ããŒãã«ãª
databaseãªããžã§ã¯ããäœæãããŸãã startupã€ãã³ããã³ãã©ã¯await database.connect()ãåŒã³åºããæ¥ç¶ããŒã«ãåæåããŸããshutdownã€ãã³ããã³ãã©ã¯await database.disconnect()ãåŒã³åºãããã¹ãŠã®æ¥ç¶ãã¯ãªãŒã³ã«éããŸãã
ã¹ããã2ïŒéåæCRUDãšã³ããã€ã³ãã®å®è£
次ã«ãäœæãèªã¿åããæŽæ°ãåé€ïŒCRUDïŒæäœãå®è¡ãããšã³ããã€ã³ãã远å ããŸãããããŸããããŒã¿ã®æ€èšŒãšã·ãªã¢ã©ã€ãŒãŒã·ã§ã³ã«ã¯Pydanticã䜿çšããŸãã
以äžã®ã³ãŒããmain_databases.pyãã¡ã€ã«ã«è¿œå ããŠãã ããïŒ
from pydantic import BaseModel
from typing import List, Optional
# --- Pydantic Models for data validation ---
class NoteIn(BaseModel):
title: str
content: str
class Note(BaseModel):
id: int
title: str
content: str
# --- CRUD Endpoints ---
@app.post("/notes/", response_model=Note)
async def create_note(note: NoteIn):
"""Create a new note in the database."""
query = notes.insert().values(title=note.title, content=note.content)
last_record_id = await database.execute(query)
return {**note.dict(), "id": last_record_id}
@app.get("/notes/", response_model=List[Note])
async def read_all_notes():
"""Retrieve all notes from the database."""
query = notes.select()
return await database.fetch_all(query)
@app.get("/notes/{note_id}", response_model=Note)
async def read_note(note_id: int):
"""Retrieve a single note by its ID."""
query = notes.select().where(notes.c.id == note_id)
result = await database.fetch_one(query)
if result is None:
raise HTTPException(status_code=404, detail="Note not found")
return result
@app.put("/notes/{note_id}", response_model=Note)
async def update_note(note_id: int, note: NoteIn):
"""Update an existing note."""
query = (
notes.update()
.where(notes.c.id == note_id)
.values(title=note.title, content=note.content)
)
result = await database.execute(query)
if result == 0:
raise HTTPException(status_code=404, detail="Note not found")
return {**note.dict(), "id": note_id}
@app.delete("/notes/{note_id}")
async def delete_note(note_id: int):
"""Delete a note by its ID."""
query = notes.delete().where(notes.c.id == note_id)
result = await database.execute(query)
if result == 0:
raise HTTPException(status_code=404, detail="Note not found")
return {"message": "Note deleted successfully"}
éåæåŒã³åºãã®åæïŒ
await database.execute(query)ïŒINSERTãUPDATEãDELETEãªã©ãè¡ãè¿ããªãæäœã«äœ¿çšãããŸãã圱é¿ãåããè¡æ°ãŸãã¯æ°ããã¬ã³ãŒãã®äž»ããŒãè¿ããŸããawait database.fetch_all(query)ïŒè€æ°ã®è¡ãæåŸ ãããSELECTã¯ãšãªã«äœ¿çšãããŸããã¬ã³ãŒãã®ãªã¹ããè¿ããŸããawait database.fetch_one(query)ïŒæå€§ã§1ã€ã®è¡ãæåŸ ãããSELECTã¯ãšãªã«äœ¿çšãããŸããåäžã®ã¬ã³ãŒããŸãã¯Noneãè¿ããŸãã
ãã¹ãŠã®ããŒã¿ããŒã¹æäœã®åã«awaitãä»ããŠããããšã«æ³šæããŠãã ãããããããããŒã¿ããŒã¹ãå¿çããã®ãåŸ
ã€éã«ã€ãã³ãã«ãŒããä»ã®ã¿ã¹ã¯ã«åãæ¿ããããšãå¯èœã«ããé«ãäžŠè¡æ§ãå®çŸããéæ³ã§ãã
æŠç¥2ïŒçŸä»£ã®åŒ·åãªããŒã« - SQLAlchemy 2.0+ éåæORM
databasesã©ã€ãã©ãªã¯ã·ã³ãã«ã§çŽ æŽãããã§ãããå€ãã®å€§èŠæš¡ã¢ããªã±ãŒã·ã§ã³ã¯ããã«æ©èœã®ãªããžã§ã¯ããªã¬ãŒã·ã§ãã«ããããŒïŒORMïŒã®æ©æµãåããŸããORMã䜿çšãããšãããŒã¿ããŒã¹ã¬ã³ãŒããPythonãªããžã§ã¯ããšããŠæ±ãããšãã§ããéçºè
ã®çç£æ§ãšã³ãŒãã®ä¿å®æ§ã倧å¹
ã«åäžãããããšãã§ããŸããSQLAlchemyã¯Pythonçã§æã匷åãªORMã§ããããã®2.0以äžã®ããŒãžã§ã³ã¯æå
端ã®ãã€ãã£ãéåæã€ã³ã¿ãŒãã§ãŒã¹ãæäŸããŸãã
ã¹ããã1ïŒéåæãšã³ãžã³ãšã»ãã·ã§ã³ã®ã»ããã¢ãã
SQLAlchemyã®éåææ©èœã®äžæ žã¯AsyncEngineãšAsyncSessionã«ãããŸããã»ããã¢ããã¯åæçããŒãžã§ã³ãšã¯å°ãç°ãªããŸãã
ããè¯ãæ§é ã«ããããã«ãã³ãŒããããã€ãã®ãã¡ã€ã«ã«æŽçããŸãïŒdatabase.pyãmodels.pyãschemas.pyããããŠmain_sqlalchemy.pyã§ãã
database.pyïŒ
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
DATABASE_URL = "postgresql+asyncpg://user:password@localhost/testdb"
# Create an async engine
engine = create_async_engine(DATABASE_URL, echo=True)
# Create a session factory
# expire_on_commit=False prevents attributes from being expired after commit
AsyncSessionLocal = sessionmaker(
bind=engine, class_=AsyncSession, expire_on_commit=False
)
models.pyïŒ
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class Note(Base):
__tablename__ = "notes"
id = Column(Integer, primary_key=True, index=True)
title = Column(String(100), index=True)
content = Column(String(500))
schemas.py (Pydantic models)ïŒ
from pydantic import BaseModel
class NoteBase(BaseModel):
title: str
content: str
class NoteCreate(NoteBase):
pass
class Note(NoteBase):
id: int
class Config:
orm_mode = True
Pydanticã¢ãã«ã®Configã¯ã©ã¹ã«ãã`orm_mode = True`ã¯ãéèŠãªéæ³ã®äžéšã§ããããã«ãããPydanticã¯èŸæžããã ãã§ãªããORMã¢ãã«ã®å±æ§ãããããŒã¿ãèªã¿åãããã«æç€ºãããŸãã
ã¹ããã2ïŒäŸåæ§æ³šå ¥ã«ããã»ãã·ã§ã³ç®¡ç
FastAPIã§ããŒã¿ããŒã¹ã»ãã·ã§ã³ã管çããæšå¥šæ¹æ³ã¯ãäŸåæ§æ³šå ¥ïŒDependency InjectionïŒã䜿çšããããšã§ããåäžã®ãªã¯ãšã¹ãã«å¯ŸããŠããŒã¿ããŒã¹ã»ãã·ã§ã³ãæäŸãããšã©ãŒãçºçããå Žåã§ããã®åŸç¢ºå®ã«éããããããã«ããäŸåé¢ä¿ãäœæããŸãã
ãããmain_sqlalchemy.pyã«è¿œå ããŠãã ããïŒ
from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from . import models, schemas
from .database import engine, AsyncSessionLocal
app = FastAPI()
# --- Dependency for getting a DB session ---
async def get_db() -> AsyncSession:
async with AsyncSessionLocal() as session:
try:
yield session
finally:
await session.close()
# --- Database Initialization (for creating tables) ---
@app.on_event("startup")
async def startup_event():
print("Initializing database schema...")
async with engine.begin() as conn:
# await conn.run_sync(models.Base.metadata.drop_all)
await conn.run_sync(models.Base.metadata.create_all)
print("Database schema initialized.")
get_dbäŸåé¢ä¿ã¯ããã®ãã¿ãŒã³ã®åºç€ã§ããããã䜿çšãããšã³ããã€ã³ããžã®åãªã¯ãšã¹ãã«å¯ŸããŠã次ã®ããšãè¡ããŸãïŒ
- æ°ãã
AsyncSessionãäœæããŸãã - ãšã³ããã€ã³ã颿°ã«ã»ãã·ã§ã³ã
yieldããŸãã finallyãããã¯å ã®ã³ãŒãã¯ããªã¯ãšã¹ããæåãããã©ããã«é¢ããããã»ãã·ã§ã³ãéããããæ¥ç¶ãããŒã«ã«è¿ãããããšãä¿èšŒããŸãã
ã¹ããã3ïŒSQLAlchemy ORMã«ããéåæCRUDã®å®è£
ããã§ãšã³ããã€ã³ããäœæã§ããŸãããããã¯çã®SQLã¢ãããŒããããã¯ãªãŒã³ã§ããããªããžã§ã¯ãæåã«èŠããã§ãããã
ãããã®ãšã³ããã€ã³ããmain_sqlalchemy.pyã«è¿œå ããŠãã ããïŒ
@app.post("/notes/", response_model=schemas.Note)
async def create_note(
note: schemas.NoteCreate, db: AsyncSession = Depends(get_db)
):
db_note = models.Note(title=note.title, content=note.content)
db.add(db_note)
await db.commit()
await db.refresh(db_note)
return db_note
@app.get("/notes/", response_model=list[schemas.Note])
async def read_all_notes(skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(models.Note).offset(skip).limit(limit))
notes = result.scalars().all()
return notes
@app.get("/notes/{note_id}", response_model=schemas.Note)
async def read_note(note_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(models.Note).filter(models.Note.id == note_id))
db_note = result.scalar_one_or_none()
if db_note is None:
raise HTTPException(status_code=404, detail="Note not found")
return db_note
@app.put("/notes/{note_id}", response_model=schemas.Note)
async def update_note(
note_id: int, note: schemas.NoteCreate, db: AsyncSession = Depends(get_db)
):
result = await db.execute(select(models.Note).filter(models.Note.id == note_id))
db_note = result.scalar_one_or_none()
if db_note is None:
raise HTTPException(status_code=404, detail="Note not found")
db_note.title = note.title
db_note.content = note.content
await db.commit()
await db.refresh(db_note)
return db_note
@app.delete("/notes/{note_id}")
async def delete_note(note_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(models.Note).filter(models.Note.id == note_id))
db_note = result.scalar_one_or_none()
if db_note is None:
raise HTTPException(status_code=404, detail="Note not found")
await db.delete(db_note)
await db.commit()
return {"message": "Note deleted successfully"}
SQLAlchemyéåæãã¿ãŒã³ã®åæïŒ
db: AsyncSession = Depends(get_db)ïŒããã«ãããããŒã¿ããŒã¹ã»ãã·ã§ã³ããšã³ããã€ã³ãã«æ³šå ¥ãããŸããawait db.execute(...)ïŒã¯ãšãªãå®è¡ããããã®äž»èŠãªã¡ãœããã§ããresult.scalars().all()/result.scalar_one_or_none()ïŒãããã®ã¡ãœããã¯ãã¯ãšãªçµæããå®éã®ORMãªããžã§ã¯ããæœåºããããã«äœ¿çšãããŸããdb.add(obj)ïŒæ¿å ¥ããããªããžã§ã¯ããã¹ããŒãžã³ã°ããŸããawait db.commit()ïŒéåæã§ãã©ã³ã¶ã¯ã·ã§ã³ãããŒã¿ããŒã¹ã«ã³ãããããŸããããã¯éèŠãª`await`ãã€ã³ãã§ããawait db.refresh(obj)ïŒã³ãããåŸã«ããŒã¿ããŒã¹ããã®æ°ããããŒã¿ïŒèªåçæãããIDãªã©ïŒã§Pythonãªããžã§ã¯ããæŽæ°ããŸãã
ããã©ãŒãã³ã¹ã«é¢ããèæ ®äºé ãšãã¹ããã©ã¯ãã£ã¹
`async`ãš`await`ã䜿çšããã ãã§ã¯çŽ æŽãããã¹ã¿ãŒãã§ãããçã«å ç¢ã§é«æ§èœãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã«ã¯ããããã®ãã¹ããã©ã¯ãã£ã¹ãèæ ®ããŠãã ããã
1. æ¥ç¶ããŒãªã³ã°ãçè§£ãã
databasesãšSQLAlchemyã®AsyncEngineã¯ã©ã¡ãããããã¯ã°ã©ãŠã³ãã§æ¥ç¶ããŒã«ã管çããŸãããã®ããŒã«ã¯ãç°ãªããªã¯ãšã¹ãã§åå©çšã§ããéããããŒã¿ããŒã¹æ¥ç¶ã®ã»ãããç¶æããŸããããã«ããããã¹ãŠã®ã¯ãšãªããšã«æ°ããTCPæ¥ç¶ã確ç«ããããŒã¿ããŒã¹ã§èªèšŒãããšããé«äŸ¡ãªãªãŒããŒããããåé¿ã§ããŸããç¹å®ã®ã¯ãŒã¯ããŒãã«åãããŠããšã³ãžã³èšå®ã§ããŒã«ãµã€ãºïŒäŸïŒ`pool_size`ã`max_overflow`ïŒã調æŽã§ããŸãã
2. åæãšéåæã®ããŒã¿ããŒã¹åŒã³åºããæ··ããªã
æãéèŠãªã«ãŒã«ã¯ã`async def`颿°å ã§åæçã§ããããã³ã°ãªI/O颿°ã決ããŠåŒã³åºããªãããšã§ããæšæºçãªåæããŒã¿ããŒã¹åŒã³åºãïŒäŸïŒ`psycopg2`ãçŽæ¥äœ¿çšïŒã¯ãã€ãã³ãã«ãŒãå šäœããããã¯ããã¢ããªã±ãŒã·ã§ã³ãããªãŒãºãããéåæã®ç®çãç¡æå³ã«ããŸãã
ã©ãããŠãåæçãªã³ãŒãïŒããããCPUããŠã³ããªã©ã€ãã©ãªïŒãå®è¡ããå¿ èŠãããå Žåã¯ãFastAPIã®`run_in_threadpool`ã䜿çšããŠã€ãã³ãã«ãŒãã®ããããã³ã°ãåé¿ããŠãã ããïŒ
from fastapi.concurrency import run_in_threadpool
@app.get("/run-sync-task/")
async def run_sync_task():
# 'some_blocking_io_function' is a regular sync function
result = await run_in_threadpool(some_blocking_io_function, arg1, arg2)
return {"result": result}
3. éåæãã©ã³ã¶ã¯ã·ã§ã³ã䜿çšãã
ããæäœããæåãŸãã¯å€±æãäžäœã§ãªããã°ãªããªãè€æ°ã®ããŒã¿ããŒã¹å€æŽïŒã¢ãããã¯æäœïŒã䌎ãå Žåããã©ã³ã¶ã¯ã·ã§ã³ã䜿çšããå¿ èŠããããŸããäž¡æ¹ã®ã©ã€ãã©ãªã¯ãéåæã³ã³ããã¹ããããŒãžã£ãéããŠããããµããŒãããŠããŸãã
`databases`ã䜿çšããå ŽåïŒ
async def transfer_funds():
async with database.transaction():
await database.execute(query_for_debit)
await database.execute(query_for_credit)
SQLAlchemyã䜿çšããå ŽåïŒ
async def transfer_funds(db: AsyncSession = Depends(get_db)):
async with db.begin(): # This starts a transaction
# Find accounts
account_from = ...
account_to = ...
# Update balances
account_from.balance -= 100
account_to.balance += 100
# The transaction is automatically committed on exiting the block
# or rolled back if an exception occurs.
4. å¿ èŠãªãã®ã ããéžæãã
ããã€ãã®ã«ã©ã ããå¿ èŠãªãå Žåã¯`SELECT *`ãé¿ããŠãã ããããããã¯ãŒã¯çµç±ã§è»¢éããããŒã¿ãå°ãªãããããšã§ãI/OåŸ æ©æéãççž®ãããŸããSQLAlchemyã§ã¯ã`options(load_only(model.col1, model.col2))`ã䜿çšããŠãååŸããã«ã©ã ãæå®ã§ããŸãã
çµè«ïŒéåæã®æªæ¥ãåãå ¥ãã
éåæããŒã¿ããŒã¹æäœãFastAPIã¢ããªã±ãŒã·ã§ã³ã«çµ±åããããšã¯ããã®å®å šãªããã©ãŒãã³ã¹ããã³ã·ã£ã«ãåŒãåºãéµã§ããã¢ããªã±ãŒã·ã§ã³ãããŒã¿ããŒã¹ãåŸ ã£ãŠããéã«ãããã¯ãããªãããã«ããããšã§ãä¿¡ããããªãã»ã©é«éã§ãã¹ã±ãŒã©ãã«ã§ãå¹ççãªãµãŒãã¹ãæ§ç¯ã§ããäžçäžã®ãŠãŒã¶ãŒããŒã¹ã«é£ãªã察å¿ã§ããŸãã
ç§ãã¡ã¯2ã€ã®åŒ·åãªæŠç¥ãæ¢ããŸããïŒ
- `databases`ã©ã€ãã©ãªã¯ãSQLãæžãããšã奜ã¿ãã·ã³ãã«ã§é«éãªéåæã€ã³ã¿ãŒãã§ãŒã¹ãå¿ èŠãšããéçºè ã«ãçŽæ¥çã§è»œéãªã¢ãããŒããæäŸããŸãã
- SQLAlchemy 2.0+ã¯ããã€ãã£ãéåæAPIãåãããã«æ©èœã§å ç¢ãªORMãæäŸããéçºè ã®çç£æ§ãšä¿å®æ§ãæéèŠã§ããè€éãªã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠçæ³çãªéžæè¢ãšãªããŸãã
ã©ã¡ããéžæãããã¯ãããžã§ã¯ãã®ããŒãºã«ãããŸãããäžå¿ãšãªãååã¯åãã§ãïŒãã³ããããã³ã°ã§èããããšããããã®ãã¿ãŒã³ãšãã¹ããã©ã¯ãã£ã¹ãæ¡çšããããšã§ãããªãã¯åã«ã³ãŒããæžããŠããã ãã§ãªããçŸä»£ã®ãŠã§ãã®é«äžŠè¡æ§èŠæ±ã«å¯Ÿå¿ããã·ã¹ãã ãèšèšããŠããã®ã§ãã仿¥ããæ¬¡ã®é«æ§èœFastAPIã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯ãå§ããéåæPythonã®åãçŽæ¥äœéšããŠãã ããã